#ifndef __LOGGER__
#define __LOGGER__

#include <cstddef>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <string>
#include <fstream>
#include <stdarg.h>

#define LOG_LEVEL(fun)\
    fun(DEBUG)       \
    fun(INFO)        \
    fun(WARN)        \
    fun(ERROR)       \
    fun(FATAL)       \
    fun(LEVEL_COUNT) 

//将日志输出到文件
#define MY_DEBUG(format, ...)\
    Logger::getLogInstance()->log(Logger::DEBUG, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define MY_INFO(format, ...)\
    Logger::getLogInstance()->log(Logger::INFO, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define MY_WARN(format, ...)\
    Logger::getLogInstance()->log(Logger::WARN, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define MY_ERROR(format, ...)\
    Logger::getLogInstance()->log(Logger::ERROR, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define MY_FATAL(format, ...)\
    Logger::getLogInstance()->log(Logger::FATAL, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define MY_LEVEL_COUNT(format, ...)\
    Logger::getLogInstance()->log(Logger::LEVEL_COUNT, __FILE__ , __LINE__, format, ##__VA_ARGS__);

//将日志输出到文件的同时打印到屏幕
#define PRINT_DEBUG(format, ...)\
    std::cout << Logger::getLogInstance()->log(Logger::DEBUG, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define PRINT_INFO(format, ...)\
    std::cout << Logger::getLogInstance()->log(Logger::INFO, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define PRINT_WARN(format, ...)\
    std::cout << Logger::getLogInstance()->log(Logger::WARN, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define PRINT_ERROR(format, ...)\
    std::cout << Logger::getLogInstance()->log(Logger::ERROR, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define PRINT_FATAL(format, ...)\
    std::cout << Logger::getLogInstance()->log(Logger::FATAL, __FILE__ , __LINE__, format, ##__VA_ARGS__);
#define PRINT_LEVEL_COUNT(format, ...)\
    std::cout << Logger::getLogInstance()->log(Logger::LEVEL_COUNT, __FILE__ , __LINE__, format, ##__VA_ARGS__);

class Logger
{
public:
    //日志级别
    enum Level
    {
    #define XX(name) name,
        LOG_LEVEL(XX)
    #undef XX
    };

    //设置日志级别
    void setLogLevel(Logger::Level level) { m_level = level; }

    //设置日志文件最大限制
    void setLogMaxSize(uint64_t size) { m_maxSize = size; }

    //获取当前时间C++11
    void getNowTime(std::string& time);

    //获取当前时间C
    void getNowTime(char* timeStamp, uint32_t size);

    //输出日志，日志类型 日志文件名 行号 日志内容
    std::string log(Logger::Level level, const char* file, int line, const char* format, ...);

    //获取日志单例类的指针
    static Logger* getLogInstance();

    //打开日志文件
    void open(const std::string& fileName);

    //关闭日志文件
    void close();

    void test()
    {
        for(int i = 0; i <= Level::LEVEL_COUNT; ++i)
        {
            std::cout << s_level[i] << std::endl;
        }
    }

private:
    Logger();
    ~Logger();

    //日志翻滚
    void _rotaate();
private:
    Logger::Level m_level;          //要打印的日志级别
    std::string m_fileName;         //文件名
    std::ofstream m_fout;           //文件流
    uint64_t m_maxSize;             //日志文件最大限制
    uint64_t m_len;                 //日志文件当前大小
    static const char* s_level[];   //日志级别字符串
    static Logger* m_logInstance;   //单例类指针
};

#endif